/**
 * 包含一些暂时不方便在用户态中实现的功能，在实际移植的时候需要进行替换。
 */
#ifndef _STUBS_H_
#define _STUBS_H_

/// 由1到单个内存页的大小需要左移的位数。
#define PAGE_SHIFT  12

/// 对原子变量的替代实现。
#include <stdatomic.h>

/// 由物理地址到恒等映射区的偏移
#define KERNEL_OFFSET   (1UL << 26)

/// 由恒等映射区的虚拟地址到物理地址的转换。
#define VIRT_TO_PHY(virtual)    ({  \
    unsigned long physical = 0; \
    if (virtual != NULL) {  \
        physical = (unsigned long)(virtual) - KERNEL_OFFSET;    \
    }   \
    physical;   \
})
/// 由物理地址到恒等映射区的虚拟地址的转换
#define PHY_TO_VIRT(physical)    ({  \
    unsigned long virtual = 0;  \
    if (physical != 0) {    \
        virtual = (unsigned long)(physical) + KERNEL_OFFSET;    \
    }   \
    (void *)virtual;    \
})

/// 对自旋锁的替代实现。
struct spinlock_t {
    atomic_long lock;   /// 为0时空闲，为1时被占用。
};

/// 将自旋锁初始化到空闲状态。
static inline void init_spinlock_t(
    struct spinlock_t *lock
)
{
    atomic_init(&lock->lock, 0);
}

/// 获得自旋锁
static inline int spinlock_acquire(
    struct spinlock_t *lock
)
{
    atomic_long tmp = ATOMIC_VAR_INIT(0);
    do {
        atomic_store(&tmp, 0);
        while (atomic_load(&lock->lock) != 0);
    } while (!atomic_compare_exchange_weak(&lock->lock, &tmp, 1));
}

/// 释放自旋锁
static inline int spinlock_release(
    struct spinlock_t *lock
)
{
    atomic_long tmp = ATOMIC_VAR_INIT(1);
    do {
        atomic_store(&tmp, 1);
        while (atomic_load(&lock->lock) != 1);
    } while (!atomic_compare_exchange_weak(&lock->lock, &tmp, 0));
}

/// 获得自旋锁持有状态。
static inline int is_spinlock_locked(
    struct spinlock_t *lock
)
{
    return atomic_load(&lock->lock) != 0;
}

#endif
